package com.navinfo.tripanalysis.common.arithmetic;

import com.navinfo.tripanalysis.common.arithmetic.common.*;
import com.navinfo.tripanalysis.common.arithmetic.custom.VarBrake;
import com.navinfo.tripanalysis.common.arithmetic.convert.EventDataConvert;
import com.navinfo.tripanalysis.common.arithmetic.manager.AbstractArithmetic;
import com.navinfo.tripanalysis.common.config.ConfigMap;
import com.navinfo.tripanalysis.common.protocol.java.EventDataPb;
import com.navinfo.tripanalysis.common.util.ArithmeticUtils;

import java.util.Optional;

/**
 * 刹车相关算法<br/>
 * 依赖{@link Mileage}里程油耗算法<br/>
 * 赋值{@link CommonData#brakeNumber}累积刹车次数<br/>
 * 输出：统计、事件<br/>
 */
public class Brake extends AbstractArithmetic<VarBrake> {
    /**
     * 事件类型
     */
    private static final EventDataPb.EventType EVENT_TYPE = EventDataPb.EventType.brake;
    /**
     * 刹车的速度阀值(单位：km/h)
     */
    private int speedThreshold = ConfigMap.getInteger("Brake_Speed_Threshold");
    /**
     * 异常刹车事件,速度阀值(单位：km/h)
     */
    private int eventSpeedThreshold = ConfigMap.getInteger("Brake_Event_Speed_Threshold");
    /**
     * 异常刹车事件，时长阀值(单位：ms）
     */
    private long eventDurationThreshold = ConfigMap.getLong("Brake_Event_Duration_Threshold");

    /**
     * 判断当前点是否为刹车状态
     */
    boolean isCurrentBrake() {
        CommonData data = getCommonData();
        //刹车打开 and 速度>阀值
        return (data.getBrake()==0x01 && data.getSpeedKmh()>speedThreshold);
    }

    /**
     * 判断当前点是否为异常刹车状态
     */
    boolean isCurrentEventBrake() {
        CommonData data = getCommonData();
        //刹车打开 and 速度>阀值
        return (data.getBrake()==0x01 &&data.getSpeedKmh()>eventSpeedThreshold);
    }

    @Override
    public void calculate() {
        logger.debug("进入制动算法.[terminalId:{}]", terminalId);
        VarBrake var = getObj();
        CommonData commonData = getCommonData();

        //刹车算法计算
        boolean previousBrake = var.isPreBrake();
        boolean currentBrake = isCurrentBrake();
        var.setPreBrake(currentBrake);
        logger.debug("制动算法，制动状态：previousBrake:{},currentBrake:{}.[terminalId:{}]", previousBrake, currentBrake, terminalId);

        switch (super.getEventStatus(previousBrake, currentBrake)) {
            case START:
                logger.debug("制动算法，事件开始.[terminalId:{}]", terminalId);
                //制动次数+1
                commonData.setBrakeNumber(commonData.getBrakeNumber() + 1);
                break;
            case IN:
                logger.debug("制动算法，事件中.[terminalId:{}]", terminalId);
                calcBrake();
                break;
            case END:
                logger.debug("制动算法，事件结束.[terminalId:{}]", terminalId);
                calcBrake();
                break;
            default:
                logger.debug("制动算法，制动状态：上一次和本次都未制动，不进行计算.[terminalId:{}]", terminalId);
        }

        //异常刹车算法计算
        boolean preEventBrake = var.isPreEventBrake();
        boolean curEventBrake = isCurrentEventBrake();
        var.setPreEventBrake(curEventBrake);
        logger.debug("制动算法，制动状态：preEventBrake:{},curEventBrake:{}.[terminalId:{}]", preEventBrake, curEventBrake, terminalId);

        switch (super.getEventStatus(preEventBrake, curEventBrake)) {
            case START:
                logger.debug("制动算法，异常刹车事件开始.[terminalId:{}]", terminalId);
                startEventData(EVENT_TYPE);
                break;
            case IN:
                logger.debug("制动算法，异常刹车事件中.[terminalId:{}]", terminalId);
                calcEventData(EVENT_TYPE);
                break;
            case END:
                logger.debug("制动算法，异常刹车事件结束.[terminalId:{}]", terminalId);
                calcEventData(EVENT_TYPE);
                endEvent();
                break;
            default:
                logger.debug("制动算法，异常刹车状态：上一次和本次都未异常刹车，不进行计算.[terminalId:{}]", terminalId);
        }

        //行程结束时要清理对应的未结束事件
        if (commonData.isTripLastNode()) {
            endEvent();
        }

        logger.debug("制动算法结束.[terminalId:{}]", terminalId);
    }


    @Override
    public void collect(OuterStatisticData statisticDataOut) {
        VarBrake varBrake = getObj();
        statisticDataOut.setBrakeNumber(getCommonData().getBrakeNumber());
        statisticDataOut.setBrakeMileage(ArithmeticUtils.mileageMToM(varBrake.getMileage()));
        statisticDataOut.setBrakeDuration(ArithmeticUtils.timeMsToSecond(varBrake.getTimeMs()));
    }

    /**
     * 累积刹车的里程和时长
     */
    private void calcBrake() {
        VarBrake varBrake = getObj();
        CommonData commonData = getCommonData();
        varBrake.setMileage(varBrake.getMileage() + commonData.getDffDistance());
        varBrake.setTimeMs(varBrake.getTimeMs() + commonData.getDffTime());
    }

    /**
     * 处理异常事件的结束状态
     */
    private void endEvent() {
        Optional.ofNullable(drivingData.getEventData(EVENT_TYPE)).ifPresent(eventData -> {
            EventDataConvert.convertEnd(eventData, drivingData);
            drivingData.removeEventData(EVENT_TYPE);

            //事件时长 单位：ms
            long durations = Optional.ofNullable(eventData.getDuration()).orElse(0L);
            if (durations >= eventDurationThreshold) {
                //放入事件输出列表中
                drivingData.addEventDataToList(eventData);
                logger.debug("制动算法，事件时间{},大于事件阀值，输出事件。[terminalId:{}]", durations, terminalId);
            } else {
                logger.debug("制动算法，事件时间{},小于事件阀值，丢弃，不输出事件。[terminalId:{}]", durations, terminalId);
            }
        });
    }
}
